﻿using EMall.Domain;
using EMall.Events;
using Microsoft.EntityFrameworkCore;
namespace EMall.Uow
{
    public class PublishEventEfCoreUnitOfWork<TDbContext> : EfCoreUnitOfWork<TDbContext>
        where TDbContext : DbContext
    {
        private readonly IEventBus _eventBus;
        public PublishEventEfCoreUnitOfWork(TDbContext dbContext, IEventBus eventBus) : base(dbContext)
        {
            ArgumentNullException.ThrowIfNull(eventBus, nameof(eventBus));
            _eventBus = eventBus;
        }
        public override async Task OnCommitExecutingAsync()
        {
            await SaveChangesAndPublishEventsAsync();
        }
        private async Task SaveChangesAndPublishEventsAsync()
        {
            if (_dbContext.ChangeTracker.HasChanges())
            {
                await _dbContext.SaveChangesAsync();
                var aggregateRoots = _dbContext.ChangeTracker.Entries<IAggregateRoot>().Select(o => o.Entity).Where(o => o.DomainEvents.Any()).ToList();
                if (aggregateRoots.Any())
                {
                    foreach (var aggregateRoot in aggregateRoots)
                    {
                        foreach (var domainEvent in aggregateRoot.DomainEvents)
                        {
                            await _eventBus.PublishAsync(domainEvent);
                        }
                        aggregateRoot.ClearDomainEvents();
                    }
                    await SaveChangesAndPublishEventsAsync();
                }
            }
        }
    }
}
